import { ref, onMounted, onUnmounted } from 'vue'

export interface LazyImageOptions {
  rootMargin?: string
  threshold?: number
  placeholder?: string
  errorImage?: string
  loadingClass?: string
  loadedClass?: string
  errorClass?: string
}

export interface LazyImageState {
  isLoading: boolean
  isLoaded: boolean
  hasError: boolean
  currentSrc: string
}

export function useLazyImage(
  src: string,
  options: LazyImageOptions = {}
) {
  const defaultOptions: Required<LazyImageOptions> = {
    rootMargin: '50px',
    threshold: 0.1,
    placeholder: '',
    errorImage: '/image-error.png',
    loadingClass: 'lazy-loading',
    loadedClass: 'lazy-loaded',
    errorClass: 'lazy-error'
  }

  const config = { ...defaultOptions, ...options }

  // Refs
  const imageRef = ref<HTMLImageElement>()
  const isLoading = ref(false)
  const isLoaded = ref(false)
  const hasError = ref(false)
  const currentSrc = ref(config.placeholder)

  // State
  const state = ref<LazyImageState>({
    isLoading: false,
    isLoaded: false,
    hasError: false,
    currentSrc: config.placeholder
  })

  // Observer
  let observer: IntersectionObserver | null = null

  const loadImage = async () => {
    if (isLoaded.value || isLoading.value || !src) return

    isLoading.value = true
    hasError.value = false
    state.value.isLoading = true
    state.value.hasError = false

    try {
      const img = new Image()
      
      await new Promise<void>((resolve, reject) => {
        img.onload = () => resolve()
        img.onerror = () => reject(new Error('Image load failed'))
        img.src = src
      })

      // Image loaded successfully
      currentSrc.value = src
      isLoaded.value = true
      isLoading.value = false
      
      state.value.currentSrc = src
      state.value.isLoaded = true
      state.value.isLoading = false

      // Update image element classes
      if (imageRef.value) {
        imageRef.value.classList.remove(config.loadingClass)
        imageRef.value.classList.add(config.loadedClass)
      }

    } catch (error) {
      // Image load failed
      currentSrc.value = config.errorImage
      hasError.value = true
      isLoading.value = false
      
      state.value.currentSrc = config.errorImage
      state.value.hasError = true
      state.value.isLoading = false

      // Update image element classes
      if (imageRef.value) {
        imageRef.value.classList.remove(config.loadingClass)
        imageRef.value.classList.add(config.errorClass)
      }

      console.warn('Lazy image load failed:', src, error)
    }
  }

  const setupIntersectionObserver = () => {
    if (!window.IntersectionObserver || !imageRef.value) return

    observer = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting && !isLoaded.value && !isLoading.value) {
            loadImage()
            // Stop observing once we start loading
            if (observer && imageRef.value) {
              observer.unobserve(imageRef.value)
            }
          }
        })
      },
      {
        rootMargin: config.rootMargin,
        threshold: config.threshold
      }
    )

    observer.observe(imageRef.value)
  }

  const retry = () => {
    if (hasError.value) {
      hasError.value = false
      isLoaded.value = false
      state.value.hasError = false
      state.value.isLoaded = false
      loadImage()
    }
  }

  const reset = () => {
    isLoading.value = false
    isLoaded.value = false
    hasError.value = false
    currentSrc.value = config.placeholder
    
    state.value.isLoading = false
    state.value.isLoaded = false
    state.value.hasError = false
    state.value.currentSrc = config.placeholder

    if (imageRef.value) {
      imageRef.value.classList.remove(config.loadingClass, config.loadedClass, config.errorClass)
    }
  }

  // Lifecycle
  onMounted(() => {
    if (imageRef.value) {
      // Add loading class initially
      imageRef.value.classList.add(config.loadingClass)
      
      // Setup intersection observer for lazy loading
      setupIntersectionObserver()
    }
  })

  onUnmounted(() => {
    if (observer) {
      observer.disconnect()
    }
  })

  return {
    // Refs
    imageRef,
    
    // State
    isLoading: readonly(isLoading),
    isLoaded: readonly(isLoaded),
    hasError: readonly(hasError),
    currentSrc: readonly(currentSrc),
    state: readonly(state),
    
    // Methods
    loadImage,
    retry,
    reset
  }
}

// Composable for multiple images lazy loading
export function useLazyImageBatch(
  images: Array<{ id: string; src: string; options?: LazyImageOptions }>
) {
  const imageStates = ref<Map<string, LazyImageState>>(new Map())
  const loadedCount = ref(0)
  const totalCount = ref(images.length)

  const getImageState = (id: string): LazyImageState | undefined => {
    return imageStates.value.get(id)
  }

  const isAllLoaded = computed(() => {
    return loadedCount.value === totalCount.value
  })

  const loadProgress = computed(() => {
    return totalCount.value > 0 ? (loadedCount.value / totalCount.value) * 100 : 0
  })

  const updateImageState = (id: string, state: LazyImageState) => {
    const oldState = imageStates.value.get(id)
    imageStates.value.set(id, state)
    
    // Update loaded count
    if (!oldState?.isLoaded && state.isLoaded) {
      loadedCount.value++
    } else if (oldState?.isLoaded && !state.isLoaded) {
      loadedCount.value--
    }
  }

  const resetAll = () => {
    imageStates.value.clear()
    loadedCount.value = 0
    totalCount.value = images.length
  }

  return {
    // State
    imageStates: readonly(imageStates),
    loadedCount: readonly(loadedCount),
    totalCount: readonly(totalCount),
    isAllLoaded,
    loadProgress,
    
    // Methods
    getImageState,
    updateImageState,
    resetAll
  }
}

// Utility function to preload images
export async function preloadImages(urls: string[]): Promise<void> {
  const promises = urls.map(url => {
    return new Promise<void>((resolve, reject) => {
      const img = new Image()
      img.onload = () => resolve()
      img.onerror = () => reject(new Error(`Failed to preload image: ${url}`))
      img.src = url
    })
  })

  try {
    await Promise.all(promises)
  } catch (error) {
    console.warn('Some images failed to preload:', error)
  }
}